#! python3
# -*- coding: utf-8 -
'''
Created on 2020年05月10日
@author: zxyong 13738196011
'''
import time, binascii, struct,random
from com.zxy.common import Com_Para
from com.zxy.common.Com_Fun import Com_Fun
import modbus_tk.defines as cst
import modbus_tk.modbus_rtu as modbus_rtu
from com.zxy.z_debug import z_debug
class ComModBus(z_debug):
    def __init__(self):
        pass
    @staticmethod
    def get_objAryRtuMaster(inputComPort):        
        master = Com_Fun.GetHashTableNone(Com_Para.objAryRtuMaster, inputComPort)
        if master is None:
            com_at = Com_Fun.GetHashTableNone(Com_Para.htComPort, inputComPort)
            if com_at is not None:
                master = modbus_rtu.RtuMaster(com_at.attSerial)           
                master.set_timeout(5.0)
                master.set_verbose(True)
                Com_Fun.SetHashTable(Com_Para.objAryRtuMaster, inputComPort, master)
        return master
    @staticmethod
    def get_data_com(inputComPort, CmdStr):         
        try:  
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes().fromhex(CmdStr)
            inputByte = inputByte + ComModBus._getCrc16(inputByte)
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = str(binascii.b2a_hex(comValue))[2:-1]                 
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = comValue
        return temReturn
    @staticmethod
    def get_data_com_value_immed(inputComPort, CmdStr):         
        try:  
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)
            inputByte2 = bytes(CmdStr, encoding="utf8")
            if com_at.WritePortDataImmed(inputByte2) > 0:
                com_at.attReturnValue = None
        except Exception as e:
            pass
    @staticmethod
    def get_data_com_hex_flag(inputComPort, CmdStr,EndFlag):         
        try:
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes().fromhex(CmdStr)
            if com_at.WritePortDataFlag(inputByte,EndFlag) > 0:
                comValue = com_at.attReturnValue
                com_at.attReturnValue = None
                if comValue is None:
                    return None
                temReturn = comValue
        except Exception as e:
            temReturn = None
        return temReturn
    @staticmethod
    def get_data_com_hex(inputComPort, CmdStr):         
        try:
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes().fromhex(CmdStr)
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = comValue
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    @staticmethod
    def get_data_com_byteinit(inputComPort, inputByte):         
        try:
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = comValue
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    @staticmethod
    def get_data_com_byte(inputComPort, CmdStr):         
        try:
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes(CmdStr, encoding="utf8")
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = comValue
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = None
        return temReturn
    @staticmethod
    def get_data_com_value(inputComPort, CmdStr):         
        try:  
            com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  
            inputByte = bytes(CmdStr, encoding="utf8")
            if com_at.WritePortData(inputByte) > 0:
                comValue = com_at.attReturnValue
                if comValue is None:
                    return None
                temReturn = str(comValue, encoding="utf-8")
                com_at.attReturnValue = None
        except Exception as e:
            temReturn = -1
        return temReturn
    @staticmethod
    def get_data_rtu_random(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):
        red = []
        try:
            red = [0]*inputModbusLength
            i = 0
            for k in red:
                red[i] = round(random.uniform(100.00,500.00),4)
                i = i + 1
            return red
        except Exception as e:
            return [""]
    @staticmethod
    def get_data_rtu_04(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):
        red = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                red = master.execute(inputModbusAddr, cst.READ_INPUT_REGISTERS, inputModbusBegin, inputModbusLength)  # 这里可以修改需要读取的功能码             
                time.sleep(0.1)
            if isinstance(red, list) or isinstance(red, tuple): 
                return red
            else:
                return [""]
        except Exception as e:
            return [""]
    @staticmethod
    def get_data_rtu(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):
        red = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                red = master.execute(inputModbusAddr, cst.READ_HOLDING_REGISTERS, inputModbusBegin, inputModbusLength)  # 这里可以修改需要读取的功能码             
                time.sleep(0.1)
            if isinstance(red, list) or isinstance(red, tuple): 
                return red
            else:
                return [""]
        except Exception as e:
            return [""]
    @staticmethod
    def set_data_rtu(inputComPort, inputModbusAddr, inputModbusBegin, inputValue):
        red = []
        try:
            master = ComModBus.get_objAryRtuMaster(inputComPort)
            if master is not None:
                if isinstance(inputValue, list) or isinstance(red, tuple):
                    red = master.execute(inputModbusAddr, cst.WRITE_MULTIPLE_REGISTERS, inputModbusBegin, output_value=inputValue) 
                else:
                    red = master.execute(inputModbusAddr, cst.WRITE_SINGLE_REGISTER, inputModbusBegin, output_value=inputValue)               
            if isinstance(red, list) or isinstance(red, tuple): 
                return red
            else:
                return [""]
        except Exception as e:
            return [""]
    @staticmethod
    def CheckCRC16Z(inputData):
        usDataLen = b''
        usDataLen = bytes(inputData, encoding=Com_Para.U_CODE)
        crc_reg = 0xFFFF
        for i in usDataLen:
            crc_reg = ( crc_reg >> 8) ^ i
            for j in range(8):
                check = crc_reg & 0x0001
                crc_reg >>= 1
                if check == 0x0001 :
                    crc_reg ^= 0xA001
        temV = hex(crc_reg)[2:6]
        if len(temV) == 3:
            temV = "0"+temV 
        elif len(temV) == 2:
            temV = "00"+temV
        elif len(temV) == 1:
            temV = "000"+temV
        return temV
    @staticmethod
    def _getCrc16(RtuStr):
        b = 0xA001
        a = 0xFFFF
        for byte in RtuStr:
            a = a ^ byte
            for i in range(8):
                if a & 0x0001:
                    a = a >> 1
                    a = a ^ b 
                else:
                    a = a >> 1
        aa = '0' * (6 - len(hex(a))) + hex(a)[2:]
        lo, hh = int(aa[:2], 16), int(aa[2:], 16)
        hexbytes = bytes([hh, lo])
        return hexbytes
    @staticmethod
    def ReadFloat(n1, n2, reverse=False):    
        n = '%04x' % n1
        m = '%04x' % n2
        if reverse:
            v = n + m
        else:
            v = m + n
        y_bytes = bytes.fromhex(v)
        y = struct.unpack('!f', y_bytes)[0]
        y = round(y, 6)
        return y
    @staticmethod
    def WriteFloat(self, value, reverse=False):
        y_bytes = struct.pack('!f', value)
        y_hex = ''.join(['%02x' % i for i in y_bytes])
        n, m = y_hex[:-4], y_hex[-4:]
        n, m = int(n, 16), int(m, 16)
        if reverse:
            v = [n, m]
        else:
            v = [m, n]
        return v
    @staticmethod
    def ReadDint(n1,m1, reverse=False):
        n ='%04x' % n1
        m = '%04x' % m1
        if reverse:
            v = n + m
        else:
            v = m + n
        y_bytes = bytes.fromhex(v)
        y = struct.unpack('!i', y_bytes)[0]
        return y
    @staticmethod
    def WriteDint(self, value, reverse=False):
        y_bytes = struct.pack('!i', value)
        y_hex = ''.join(['%02x' % i for i in y_bytes])
        n, m = y_hex[:-4], y_hex[-4:]
        n, m = int(n, 16), int(m, 16)
        if reverse:
            v = [n, m]
        else:
            v = [m, n]
        return v
